package com.lingyun.ucm.web.mvc.service.impl;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.I0Itec.zkclient.ZkClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.lingyun.ucm.common.exception.ServiceException;
import com.lingyun.ucm.common.exception.UtilException;
import com.lingyun.ucm.common.pojo.bean.BusinessModule;
import com.lingyun.ucm.common.pojo.bean.BusinessSystem;
import com.lingyun.ucm.common.pojo.bean.ConfigBean;
import com.lingyun.ucm.common.pojo.bean.ConfigStoreValue;
import com.lingyun.ucm.common.pojo.vo.ConfigVO;
import com.lingyun.ucm.common.pojo.vo.ModuleVO;
import com.lingyun.ucm.common.util.Constant;
import com.lingyun.ucm.common.zk.ZkClientUtil;
import com.lingyun.ucm.web.mvc.service.ConfigCenterService;
import com.lingyun.ucm.web.mvc.service.impl.configfile.ConfigFileProcessorFactory;
import com.lingyun.ucm.web.mvc.service.impl.configfile.IConfigFileProcessor;

/**
 * 
 * @author Terrence2013
 * 2018年1月24日 上午9:57:02
 * 配置中心服务实现类
 */
public class ConfigCenterServiceImpl implements ConfigCenterService {

    private static final Logger logger = LoggerFactory.getLogger(ConfigCenterServiceImpl.class);
    private ZkClient zkClient;

    /**
     * 录入properties文件中的初始化配置
     */
    @Override
    public void importConfigFile(InputStream in, String fileType) throws ServiceException {
        try {
            zkClient = ZkClientUtil.createZkClient();
            IConfigFileProcessor configIniter = ConfigFileProcessorFactory.build(fileType);
            configIniter.importConfig(in, zkClient);
        } catch (Exception e) {
            logger.error("初始化配置文件失败:{}", e.getMessage());
            throw new ServiceException(e);
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    throw new ServiceException(e);
                }
            }
            ZkClientUtil.closeZkClient(zkClient);
        }

    }

    /**
     * 新增配置
     *
     * @param systemName
     * @param moduleName
     * @param configKey
     * @param configStoreValue
     * @throws ServiceException
     */
    @Override
    public void save(String systemName, String moduleName, String configKey, ConfigStoreValue configStoreValue) throws ServiceException {
        try {
            zkClient = ZkClientUtil.createZkClient();
            String path = ZkClientUtil.getNodePath(systemName, moduleName, configKey);
            ZkClientUtil.checkPath(path);
            if (zkClient.exists(path)) {
                throw new ServiceException("配置项已存在!");
            }
            zkClient.createPersistent(path, true);//创建持久节点
            zkClient.writeData(path, JSON.toJSONString(
                    new ConfigStoreValue(configStoreValue.isCanEdit(), configStoreValue.isCanDel(), configStoreValue.getValue())));//存储节点数据
        } catch (UtilException e) {
            throw new ServiceException(e);
        } finally {
        	ZkClientUtil.closeZkClient(zkClient);
        }
    }

    /**
     * 编辑配置
     *
     * @param systemName
     * @param moduleName
     * @param configKey
     * @param configValue
     * @param oldConfigKey
     * @throws ServiceException
     */
    @Override
    public void update(String systemName, String moduleName, String configKey, String configValue, String oldConfigKey) throws ServiceException {
        try {
            zkClient = ZkClientUtil.createZkClient();
            String path = ZkClientUtil.getNodePath(systemName, moduleName, oldConfigKey);
            ZkClientUtil.checkPath(path);
            ConfigVO configVO = this.getConfigVO(path);
            ConfigStoreValue storeValue = JSON.parseObject(configVO.getConfigValue(), ConfigStoreValue.class);
            if (!storeValue.isCanEdit()) {
                throw new ServiceException("该配置不可编辑!");
            }
            if (configKey.equals(oldConfigKey)) {
                zkClient.writeData(path, JSON.toJSONString(new ConfigStoreValue(storeValue.isCanEdit(), storeValue.isCanDel(), configValue)));//存储节点数据
            } else {
                this.delete(systemName, moduleName, oldConfigKey);
                this.save(systemName, moduleName, configKey, new ConfigStoreValue(storeValue.isCanEdit(), storeValue.isCanDel(), configValue));
            }
        } catch (UtilException e) {
            throw new ServiceException(e);
        } finally {
        	ZkClientUtil.closeZkClient(zkClient);
        }
    }


    /**
     * 删除配置
     *
     * @param systemName
     * @param moduleName
     * @param key
     * @throws ServiceException
     */
    @Override
    public void delete(String systemName, String moduleName, String key) throws ServiceException {
        try {
            zkClient = ZkClientUtil.createZkClient();
            String path = ZkClientUtil.getNodePath(systemName, moduleName, key);
            ZkClientUtil.checkPath(path);
            ConfigVO configVO = this.getConfigVO(path);
            ConfigStoreValue storeValue = JSON.parseObject(configVO.getConfigValue(), ConfigStoreValue.class);
            if (!storeValue.isCanDel()) {
                throw new ServiceException("该配置不可删除!");
            }
            if (zkClient.exists(path)) {
                zkClient.delete(path);
            }
        } catch (UtilException e) {
            throw new ServiceException(e);
        } finally {
        	ZkClientUtil.closeZkClient(zkClient);
        }
    }

    /**
     * 获取列表数据
     *
     * @param path
     * @return
     */
    @Override
    public List<BusinessSystem> list(String path) throws ServiceException {
        try {
            zkClient = ZkClientUtil.createZkClient();
            List<ConfigVO> configVOList = new ArrayList<>();
            this.listAllChildrenConfig(path, configVOList);
            ArrayList<BusinessSystem> configList = new ArrayList<>();
            //筛选出系统名称和模块名称存到Set集合中
            Set<String> systemSet = new HashSet<>();
            Set<ModuleVO> moduleSet = new HashSet<>();
            for (ConfigVO configVO : configVOList) {
                String[] splits = configVO.getConfigPath().split("/");
                if (splits.length > Constant.CONFIG_SYSTEM_INDEX) {
                    String systemName = splits[Constant.CONFIG_SYSTEM_INDEX];
                    systemSet.add(systemName);
                    if (splits.length > Constant.CONFIG_MODULE_INDEX) {
                        String moduleName = splits[Constant.CONFIG_MODULE_INDEX];
                        ModuleVO moduleVO = new ModuleVO(moduleName, systemName);
                        moduleSet.add(moduleVO);
                    }
                }
            }
            //将返回的list数据封装成BusinessSystem对象
            Iterator<String> systemIterator = systemSet.iterator();
            while (systemIterator.hasNext()) {
                String systemName = systemIterator.next();
                BusinessSystem businessSystem = new BusinessSystem();
                businessSystem.setSystemName(systemName);
                List<BusinessModule> moduleList = new ArrayList<>();
                businessSystem.setModules(moduleList);
                Iterator<ModuleVO> moduleIterator = moduleSet.iterator();
                while (moduleIterator.hasNext()) {
                    ModuleVO moduleVO = moduleIterator.next();
                    String moduleName = moduleVO.getModuleName();
                    if (moduleVO.getSystemName().equals(systemName)) {
                        BusinessModule businessModule = new BusinessModule();
                        moduleList.add(businessModule);
                        businessModule.setModuleName(moduleName);
                        List<ConfigBean> configBeanList = new ArrayList<>();
                        businessModule.setConfigBeans(configBeanList);
                        Iterator<ConfigVO> configVOIterator = configVOList.iterator();
                        while (configVOIterator.hasNext()) {
                            ConfigVO configVO = configVOIterator.next();
                            String configPath = configVO.getConfigPath();
                            String[] splits = configPath.split("/");
                            if (splits[Constant.CONFIG_SYSTEM_INDEX].equals(systemName) && splits[Constant.CONFIG_MODULE_INDEX].equals(moduleName)
                                    && splits.length == Constant.CONFIG_TOTAL_LENGTH) {
                                ConfigBean configBean = new ConfigBean();
                                configBean.setConfigName(splits[Constant.CONFIG_PROPERTY_INDEX]);
                                configBean.setConfigStoreValue(JSON.parseObject(configVO.getConfigValue(), ConfigStoreValue.class));
                                configBeanList.add(configBean);
                                configVOIterator.remove();//删除已封装项减少循环次数
                            }
                        }

                    }
                }
                configList.add(businessSystem);
            }
            return configList;
        } catch (Exception e) {
            throw new ServiceException(e);
        } finally {
        	ZkClientUtil.closeZkClient(zkClient);
        }
    }

    /**
     * 获取所有业务系统名称
     *
     * @return
     */
    @Override
    public List<String> getAllSystemNames() throws ServiceException {
        try {
            zkClient = ZkClientUtil.createZkClient();
            List<String> systemNames = new ArrayList<>();
            if (zkClient.exists(Constant.ZK_ROOT_PATH)) {
                systemNames = zkClient.getChildren(Constant.ZK_ROOT_PATH);
            }
            return systemNames;
        } catch (Exception e) {
            throw new ServiceException(e);
        } finally {
        	ZkClientUtil.closeZkClient(zkClient);
        }
    }

    /**
     * 新增业务系统
     *
     * @param systemName
     * @throws ServiceException
     */
    @Override
    public void saveSystem(String systemName) throws ServiceException {
        try {
            zkClient = ZkClientUtil.createZkClient();
            if (systemName.indexOf("/") > 0) {
                throw new ServiceException("业务系统名称不合法!");
            }
            String path = Constant.ZK_ROOT_PATH + "/" + systemName;
            if (!zkClient.exists(path)) {
                zkClient.createPersistent(path, true);//创建持久节点
            }
        } finally {
        	ZkClientUtil.closeZkClient(zkClient);
        }
    }

    /**
     * 删除业务系统
     *
     * @param systemName
     */
    @Override
    public void deleteSystem(String systemName) throws ServiceException {
        try {
            zkClient = ZkClientUtil.createZkClient();
            String path = Constant.ZK_ROOT_PATH + "/" + systemName;
            if (zkClient.countChildren(path) > 0) {
                zkClient.deleteRecursive(path);
            } else {
                zkClient.delete(path);
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new ServiceException(e);
        } finally {
        	ZkClientUtil.closeZkClient(zkClient);
        }
    }

    /**
     * 删除功能模块
     *
     * @param systemName
     * @param moduleName
     * @throws ServiceException
     */
    @Override
    public void deleteModule(String systemName, String moduleName) throws ServiceException {
        try {
            zkClient = ZkClientUtil.createZkClient();
            String path = Constant.ZK_ROOT_PATH + "/" + systemName + "/" + moduleName;
            if (zkClient.countChildren(path) > 0) {
                zkClient.deleteRecursive(path);
            } else {
                zkClient.delete(path);
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new ServiceException(e);
        } finally {
        	ZkClientUtil.closeZkClient(zkClient);
        }
    }

    /**
     * 新增功能模块
     *
     * @param systemName
     * @param moduleName
     * @throws ServiceException
     */
    @Override
    public void saveModule(String systemName, String moduleName) throws ServiceException {
        try {
            zkClient = ZkClientUtil.createZkClient();
            String path = Constant.ZK_ROOT_PATH + "/" + systemName + "/" + moduleName;
            if (!zkClient.exists(path)) {
                zkClient.createPersistent(path, true);
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new ServiceException(e);
        } finally {
        	ZkClientUtil.closeZkClient(zkClient);
        }
    }

    @Override
    public String getDownloadString(String systemName) throws ServiceException {
        List<BusinessSystem> systems = this.list(Constant.ZK_ROOT_PATH + "/" + systemName);
        JSONArray systemJsonArray = new JSONArray();
        for (BusinessSystem system : systems) {
            JSONObject systemJsonObject = new JSONObject();
            List<BusinessModule> modules = system.getModules();
            JSONArray moduleJsonArray = new JSONArray();
            for (BusinessModule module : modules) {
                JSONArray configJsonArray = new JSONArray();
                JSONObject moduleJsonObject = new JSONObject();
                List<ConfigBean> configBeans = module.getConfigBeans();
                for (ConfigBean configBean : configBeans) {
                    JSONObject configJsonObject = new JSONObject();
                    ConfigStoreValue storeValue = configBean.getConfigStoreValue();
                    configJsonObject.put("name", configBean.getConfigName());
                    configJsonObject.put("value", storeValue.getValue());
                    configJsonObject.put("canEdit", storeValue.isCanEdit());
                    configJsonObject.put("canDel", storeValue.isCanDel());
                    configJsonArray.add(configJsonObject);
                }
                moduleJsonObject.put(module.getModuleName(), configJsonArray);
                moduleJsonArray.add(moduleJsonObject);
            }
            systemJsonObject.put(system.getSystemName(), moduleJsonArray);
            systemJsonArray.add(systemJsonObject);
        }
        return systemJsonArray.toJSONString();
    }

    /**
     * 递归获得所有子节点存储的配置信息,存在List<ConfigVO>中
     *
     * @param path
     * @param configList
     */
    private void listAllChildrenConfig(String path, List<ConfigVO> configList) {
        if (zkClient.countChildren(path) > 0) {
            List<String> children = zkClient.getChildren(path);//返回的String是节点名
            for (String child : children) {
                this.listAllChildrenConfig(path + "/" + child, configList);
            }
        } else if (zkClient.exists(path)) {
            ConfigVO configVO = this.getConfigVO(path);
            configList.add(configVO);
        }
    }

    /**
     * 根据path获取单个配置对象
     *
     * @param path
     * @return
     */
    private ConfigVO getConfigVO(String path) {
        ConfigVO configVO = new ConfigVO();
        String configValue = zkClient.readData(path);
        configVO.setConfigPath(path);
        configVO.setConfigValue(configValue);
        return configVO;
    }
}
